package com.chinaztt.fda.http;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;

import com.chinaztt.fda.Interface.Urls;
import com.chinaztt.fda.utils.Log;
import com.chinaztt.fda.utils.SignUtil;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class HttpRequest {
	private static final String TAG = new Throwable().getStackTrace()[0].getClassName();
	private static HttpRequest m_instance = null;
	public static final int CONNECT_TIMEOUT = 30;
	//private HttpClient m_HttpClient = null;

	private Handler mHandler;
	private static final int CALLBACK_DELAY = 100;

	private ExecutorService threadExecutor;

	public static HttpRequest getInstance() {
		if (null == m_instance)
			m_instance = new HttpRequest();
		return m_instance;
	}

	private HttpRequest() {
		BasicHttpParams httpParams = new BasicHttpParams();
		HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT * 1000);
		HttpConnectionParams.setSoTimeout(httpParams, CONNECT_TIMEOUT * 1000);
		ConnManagerParams.setTimeout(httpParams, CONNECT_TIMEOUT * 1000);
		//m_HttpClient = initHttpClient(httpParams);
		mHandler = new Handler(Looper.getMainLooper());
		threadExecutor = Executors.newCachedThreadPool();
	}

	private static HttpClient initHttpClient(HttpParams params) {
		try {
			KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
			trustStore.load(null, null);

			SSLSocketFactory sf = new SSLSocketFactoryImp(trustStore);
			sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

			HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
			HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

			SchemeRegistry registry = new SchemeRegistry();
			registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
			registry.register(new Scheme("https", sf, 443));

			ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

			return new DefaultHttpClient(ccm, params);
		} catch (Exception e) {
			return new DefaultHttpClient(params);
		}
	}

	public void post(final String uri, final ArrayList<NameValuePair> paramList,final HttpRequestListener listener) {
		if (TextUtils.isEmpty(uri) ) {
			notifyError(HttpState.ERROR_URI_NULL, listener);
			return;
		}

		threadExecutor.execute(new Runnable() {
			@Override
			public void run() {
				try {
					URI requestUri = new URI(uri);
					if(!requestUri.getPath().contains(Urls.getIntance().getListByLogo())){
						//添加签名
						String sign = SignUtil.sign(paramList);
						paramList.add(new BasicNameValuePair("sign", sign));
					}

					//打印URL
					Log.i(TAG, "" + uri);

					String params = "";
					//打印上送参数
					for(int i=0; i<paramList.size(); i++) {
						params += paramList.get(i).getName() + "=" + paramList.get(i).getValue() + "&";
					}
					Log.i(TAG, "上送参数==>" + params);

					HttpPost httpRequest = new HttpPost(uri);

					notifyStateChange(HttpState.STATE_RECEIVING,listener);

					UrlEncodedFormEntity urlEntity =  new UrlEncodedFormEntity(paramList, "UTF-8");
					httpRequest.setEntity(urlEntity);

					//header
					ArrayList<NameValuePair> headerList = new ArrayList<NameValuePair>();
					if(requestUri.getPath().contains(Urls.getIntance().getListByLogo())){
						headerList.add(new BasicNameValuePair("Content-Type","multipart/form-data"));
					}
					else{
						headerList.add(new BasicNameValuePair("Content-Type","application/x-www-form-urlencoded"));
					}

					for (int i = 0; i < headerList.size(); i++) {
						httpRequest.addHeader(headerList.get(i).getName(),
								headerList.get(i).getValue());
					}


					HttpClient httpClient = new DefaultHttpClient();

					HttpResponse httpResponse = httpClient.execute(httpRequest);

					//HttpResponse httpResponse = m_HttpClient.execute(httpRequest);
					if (httpResponse == null) {
						notifyError(HttpState.ERROR_NULL_HTTPRESPONSE,listener);

					} else {
						if (httpResponse.getStatusLine().getStatusCode() == 200) {

							String responseStr = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
							Log.i(TAG, "收到报文 ==> " + responseStr);
							try {
								JSONObject json = new JSONObject(responseStr);
								JSONObject msg = new JSONObject(json.get("msg").toString());
								if (msg.get("code").equals("0")) {
									notifySuccess(json, listener);
								}else {
									String responseMsg = msg.getString("text");
									if(TextUtils.isEmpty(responseMsg)) {
										responseMsg = HttpState.ERROR_RESPONSE_ERRCODE;
									}
									notifyError(responseMsg, listener);
								}
							} catch (JSONException e) {
								e.printStackTrace();
							}
						} else {
							notifyError(HttpState.ERROR_STATUS_CODE+httpResponse.getStatusLine().getStatusCode(), listener);
						}
					}
				} catch (ClientProtocolException e) {
					notifyError(HttpState.ERROR_CLIENT_PROTOCOL, listener);
					e.printStackTrace();
				} catch (UnsupportedEncodingException e) {
					notifyError(HttpState.ERROR_UNSUPPORTED_ENCODING, listener);
					e.printStackTrace();
				} catch (ParseException e) {
					notifyError(HttpState.ERROR_PARSE, listener);
					e.printStackTrace();
				} catch (ConnectTimeoutException e) {
					notifyError(HttpState.ERROR_CONNECT_TIMEOUT, listener);
					e.printStackTrace();
				} catch (SocketTimeoutException e) {
					notifyError(HttpState.ERROR_SOCKET_TIMEOUT, listener);
					e.printStackTrace();
				} catch (SocketException e) {
					notifyError(HttpState.ERROR_SOCKET, listener);
					e.printStackTrace();
				} catch (IOException e) {
					notifyError(HttpState.ERROR_IO_EXCEPTION, listener);
					e.printStackTrace();
				} catch (Exception e) {
					notifyError(HttpState.ERROR_EXCEPTION, listener);
					e.printStackTrace();
				}
			}
		});
	}

	private void notifySuccess(final JSONObject json,final HttpRequestListener listener) {
		if (listener != null && mHandler != null) {
			mHandler.postDelayed(new Runnable() {
				@Override
				public void run() {
					listener.onSuccess(json);
				}
			}, CALLBACK_DELAY);
		}
	}
	private void notifyError(final String errorMsg, final HttpRequestListener listener) {
		if (listener != null && mHandler != null) {
			mHandler.postDelayed(new Runnable() {
				@Override
				public void run() {
					listener.onError(HttpState.ERR_CODE_HTTP_REQUEST,errorMsg);
				}
			}, CALLBACK_DELAY);
		}
	}
	private void notifyStateChange(final String stateChangeMsg,final HttpRequestListener listener) {
		if (listener != null && mHandler != null) {
			mHandler.postDelayed(new Runnable() {
				@Override
				public void run() {
					listener.onStateChange(stateChangeMsg);
				}
			}, CALLBACK_DELAY);
		}
	}
}

@SuppressWarnings("rawtypes")
class SortByName implements Comparator {
	@Override
	public int compare(Object o1, Object o2) {
		NameValuePair s1 = (NameValuePair) o1;
		NameValuePair s2 = (NameValuePair) o2;
		if(s1.getName().compareTo(s2.getName()) < 0)
			return -1;
		else if (s1.getName().compareTo(s2.getName()) > 0) {
			return 1;
		}

		return 0;
	}
}
